package cn.itsource.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.itsource.exception.GlobalException;
import cn.itsource.listener.event.GeTuiMessageEvent;
import cn.itsource.mapper.PayOrderMapper;
import cn.itsource.pojo.bo.GeTuiBo;
import cn.itsource.pojo.bo.PayOrderBo;
import cn.itsource.pojo.bo.WXPayBo;
import cn.itsource.pojo.domain.PayOrder;
import cn.itsource.service.IPayOrderService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.cipher.Signer;
import com.wechat.pay.java.core.http.HostName;
import com.wechat.pay.java.core.http.HttpClient;
import com.wechat.pay.java.core.util.NonceUtil;
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import java.time.Instant;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;



/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author beishan
 * @since 2024-04-19
 */
@Service
public class PayOrderServiceImpl extends ServiceImpl<PayOrderMapper, PayOrder> implements IPayOrderService {

    private Signer signer;
    private  String signType;
    private  JsapiService jsapiService;
    private static final Logger logger = LoggerFactory.getLogger(JsapiServiceExtension.class);


    /**
     * 商户号
     */
    public static String merchantId = "1637705483";
    /**
     * 商户API私钥路径
     */
    public static String privateKeyPath = "D:\\办公软件\\源码学习资料\\接收的东西\\支付材料\\apiclient_key.pem";
    /**
     * 商户证书序列号
     */
    public static String merchantSerialNumber = "1B5FCE6A83E2CD2F55441857E978F8AF7B8D85F4";
    /**
     * 商户APIV3密钥
     */
    public static String apiV3Key = "KkaXVb5fYsGqN998GS8pqoCVghhrpoW6";


    @Autowired
    private ApplicationContext context;


    /**
     * 添加支付单
     *
     * @param payOrderBo
     */
    @Override
    public void addPayOrder(PayOrderBo payOrderBo) {

        PayOrder payOrder = new PayOrder();
        payOrder.setCreateTime(new Date());
        payOrder.setAmount(payOrderBo.getAmount());
        payOrder.setOrderNo(payOrderBo.getOrder_no());
        payOrder.setPayUserId(payOrderBo.getPay_user_id());
        payOrder.setSubject(payOrderBo.getSubject());
        payOrder.setPayStatus(0);
        payOrder.setPayOrderNo(IdUtil.createSnowflake(1, 1).nextIdStr());
        super.save(payOrder);

        GeTuiBo geTuiBo = GeTuiBo.builder().type(1).message(payOrder.getSubject()).customerId(payOrder.getPayUserId()).orderNo(payOrder.getOrderNo()).build();
        context.publishEvent(new GeTuiMessageEvent(geTuiBo));
    }

    /**
     * 微信支付
     *
     * @param orderNo
     * @return
     */
    @Override
    public WXPayBo pay(String orderNo) {
        if (orderNo == null){
            throw new GlobalException("参数异常");
        }
        PayOrder payOrder = super.getOne(new LambdaQueryWrapper<PayOrder>().eq(PayOrder::getOrderNo, orderNo));
        if (payOrder == null){
            throw new GlobalException("支付单为空");
        }

        if (payOrder.getPayStatus() != 0 ){
            throw new GlobalException("订单已支付");
        }

        // 使用自动更新平台证书的RSA配置
        // 一个商户号只能初始化一个配置，否则会因为重复的下载任务报错
        Config config =
                new RSAAutoCertificateConfig.Builder()
                        .merchantId(merchantId)
                        .privateKeyFromPath(privateKeyPath)
                        .merchantSerialNumber(merchantSerialNumber)
                        .apiV3Key(apiV3Key)
                        .build();
        JsapiService service = new JsapiService.Builder().config(config).build();
        // request.setXxx(val)设置所需参数，具体参数可见Request定义
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        amount.setTotal(1);
        request.setAmount(amount);
        request.setAppid("wx2b12f5643aff0fc1");
        request.setMchid(merchantId);
        request.setDescription("测试商品标题");
        request.setNotifyUrl("https://notify_url");
        request.setOutTradeNo(IdUtil.createSnowflake(1, 1).nextIdStr());
        Payer payer = new Payer();
        //TODO 支付人的openid
        payer.setOpenid("2DK6_yq759Gillo20tb49qxeD8");
        request.setPayer(payer);
        PrepayResponse response = service.prepay(request);
        System.out.println(response.getPrepayId());
        PrepayWithRequestPaymentResponse requestPaymentResponse = prepayWithRequestPayment(request);
        WXPayBo wxPayBo = new WXPayBo();
        wxPayBo.setTimeStamp(requestPaymentResponse.getTimeStamp());
        wxPayBo.setNonceStr(requestPaymentResponse.getNonceStr());
        wxPayBo.setPackageVal(requestPaymentResponse.getPackageVal());
        wxPayBo.setSignType(requestPaymentResponse.getSignType());
        wxPayBo.setPaySign(requestPaymentResponse.getPaySign());

        return wxPayBo;
    }

    public PrepayWithRequestPaymentResponse prepayWithRequestPayment(PrepayRequest request) {
        String prepayId = jsapiService.prepay(request).getPrepayId();
        long timestamp = Instant.now().getEpochSecond();
        String nonceStr = NonceUtil.createNonce(32);
        String packageVal = "prepay_id=" + prepayId;
        String message =
                request.getAppid() + "\n" + timestamp + "\n" + nonceStr + "\n" + packageVal + "\n";
        logger.debug("Message for RequestPayment signatures is[{}]", message);
        String sign = signer.sign(message).getSign();
        PrepayWithRequestPaymentResponse response = new PrepayWithRequestPaymentResponse();
        response.setAppId(request.getAppid());
        response.setTimeStamp(String.valueOf(timestamp));
        response.setNonceStr(nonceStr);
        response.setPackageVal(packageVal);
        response.setSignType("RSA");
        response.setPaySign(sign);
        return response;
    }


}
